﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

//######################################################
//
// 关键字过滤模块
// 可忽略简繁字、英文大小写、关键字之间的特殊字符
//
// 此代码可以用于任何项目而不需要通知原作者，但作者不承担
// 由使用此模块所带来的问题或风险。
// 原始作者： Doms Storage 工作组
//  http://www.domstorage.com
//  mapleaves@gmail.com 2008-9
//
//######################################################

namespace SAD.DataCenter.AntiAttack
{
    public class WordFilter
    {
        #region singleton
        private static WordFilter _instance = new WordFilter();
        public static WordFilter Instance
        {
            get { return _instance; }
        }
        #endregion

        private WordGroup[] _wordTable;

        private WordFilter()
        {
            _wordTable = new WordGroup[(int)char.MaxValue];
            loadForbiddenWords();
        }

        public FilterResult Filter(ref string source)
        {
            return Filter(ref source, '*');
        }

        /// <summary>
        /// 测试字符串是否出现屏蔽字
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public FilterResult Filter(ref string source,char replaceChar)
        {
            //NOTE:: 
            //  如果方法返回  FilterResult.Replace或者FilterResult.Banned，则原字符串的某些字会被替代为星号，替代后的字符串可以由source取得

            if (String.IsNullOrEmpty(source)) return FilterResult.Pass;

            FilterResult result = FilterResult.Pass;
            char[] tempString = null;

            int start = 0;
            for (; start < source.Length; start++)
            {
                WordGroup fw = _wordTable[fastToLower(source[start])];
                if (fw != null)
                {
                    for (int idx = 0; idx < fw.Count; idx++)
                    {
                        WordEntity we = fw.GetItem(idx);
                        int matchLength=0;
                        if (we.Word.Length==0 || checkString(source, we.Word, start + 1, out matchLength))
                        {
                            FilterResult fr = we.HandleType;
                            if (fr > result) result = fr; //记录最高级别的处理方法
                            if (fr == FilterResult.Replace || fr == FilterResult.Banned)
                            {
                                //替换关键字
                                if(tempString==null) tempString =source.ToCharArray();;
                                for (int pos = 0; pos < matchLength + 1; pos++)
                                {
                                    tempString[pos + start] = replaceChar;
                                }
                            }
                        }
                    }
                }
            }

            if (result > FilterResult.RecordOnly)
            {
                source = new string(tempString);
            }

            return result;
        }


        #region private functions

        private void loadForbiddenWords()
        {
            //NOTE::词库的格式
            //每行一词，以及处理的方式（用"R/B/E"分别表示"替换/禁止/记录"）。词与处理方式之间使用Tab键分隔
            //每个词里面的字之间可以用星号("*")表示可忽略的字符。例如"你*好"表示匹配"你好"以及"你X好"。
            //注意在英文单词的字母之间不能使用星号("*")忽略字符。

            Array.Clear(_wordTable, 0, _wordTable.Length);

            //加载禁词列表
            //FileStream stream = new FileStream(".\\words.txt", FileMode.Open, FileAccess.Read);
            //List<WordEntity> wordList = new List<WordEntity>();
            //StreamReader reader = new StreamReader(stream, Encoding.UTF8);
            //while (true)
            //{
            //    string line = reader.ReadLine();
            //    if (line == null) break;
            //    int pos = line.IndexOf('\t');
            //    if (pos > 0)
            //    {
            //        StringBuilder wordBuilder = new StringBuilder();
            //        foreach(char c in line.Substring(0, pos))
            //        {
            //            wordBuilder.Append((char)fastToLower(c)); //统一转换成小写
            //        }
            //        string word = wordBuilder.ToString();
            //        string handle = line.Substring(pos + 1,1).ToUpper();

            //        FilterResult handleType = FilterResult.Pass;
            //        switch (handle)
            //        {
            //            case "R":
            //                handleType = FilterResult.Replace;
            //                break;
            //            case "B":
            //                handleType = FilterResult.Banned;
            //                break;
            //            case "E":
            //                handleType = FilterResult.RecordOnly;
            //                break;
            //        }

            //        //添加到列表
            //        WordEntity w1 = new WordEntity()
            //        {
            //            Word = word,
            //            HandleType = handleType
            //        };

            //        //转换成繁体再加载一个
            //        WordEntity w2 = new WordEntity()
            //        {
            //            Word = Microsoft.VisualBasic.Strings.StrConv(word, Microsoft.VisualBasic.VbStrConv.TraditionalChinese, 0),
            //            HandleType = handleType
            //        };
            //        wordList.Add(w1);
            //        wordList.Add(w2);
            //    }
            //}
            //reader.Close();
            //stream.Close();

            List<WordEntity> wordList = new List<WordEntity>();
            WordEntity weTmp = null;
            foreach (var r in MainActivator.Current.FilterWords)
            {
                weTmp = new WordEntity() { Word = r.Word };
                if (r.Level >= 3)
                {
                    weTmp.HandleType = FilterResult.Banned;
                }
                else if (r.Level == 2)
                {
                    weTmp.HandleType = FilterResult.Replace;
                }
                else if (r.Level == 1)
                {
                    weTmp.HandleType = FilterResult.RecordOnly;
                }
                else if (r.Level == 0)
                {
                    weTmp.HandleType = FilterResult.Pass;
                }
                else
                {
                    weTmp.HandleType = FilterResult.Banned;
                }
                wordList.Add(weTmp);
            }

            //去除重复
            Comparison<WordEntity> cmp =
                delegate(WordEntity a, WordEntity b)
                {
                    return a.Word.CompareTo(b.Word);
                };

            wordList.Sort(cmp);
            for (int idx = wordList.Count - 1; idx > 0; idx--)
            {
                if (wordList[idx].Word == wordList[idx - 1].Word)
                {
                    wordList.RemoveAt(idx);
                }
            }

            //添加到字典
            foreach (WordEntity entity in wordList)
            {
                WordGroup item = _wordTable[(int)entity.Word[0]];
                if (item == null)
                {
                    item = new WordGroup();
                    item.AppendWord(
                        entity.Word.Substring(1), 
                        entity.HandleType);

                    _wordTable[(int)entity.Word[0]] = item;
                }
                else
                {
                    item.AppendWord(
                        entity.Word.Substring(1), 
                        entity.HandleType);
                }
            }
        }

        private bool checkString(string source, string keyword, int sourceStart, out int matchLength)
        {
            bool found = false;
            int sourceOffset = 0;
            int keyIndex = 0;
            for (; keyIndex < keyword.Length; keyIndex++)
            {
                if (sourceOffset + sourceStart >= source.Length) break; //原始字符串已经全部搜索完毕

                if (keyword[keyIndex] == '*')
                {
                    //跳过可忽略的字符
                    while (sourceOffset + sourceStart < source.Length)
                    {
                        if (isIgnorableCharacter_CN(source[sourceOffset + sourceStart]))
                            sourceOffset++;
                        else
                            break;
                    }
                }
                else
                {
                    //比较字母
                    if (fastToLower(source[sourceOffset + sourceStart]) == (int)keyword[keyIndex])
                    {
                        if (keyIndex == keyword.Length - 1)
                        {
                            found = true;
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }

                    sourceOffset++;//移动原始字符串
                }
            }

            //如果匹配中关键字，则返回原字符串中被匹配中的文字的长度，否则返回0
            matchLength = sourceOffset + 1;
            return found;
        }

        private int fastToLower(char character)
        {
            //将大写英文字母以及全/半角的英文字母转化为小写字母
            int charVal = (int)character;
            if (charVal <= 90)
            {
                if (charVal >= 65) //字母A-Z
                    return charVal - 65 + 97;
            }
            else if (charVal >= 65313)
            {
                if (charVal <= 65338)
                    return charVal - 65313 + 97; //全角大写A-Z
                else if (charVal >= 65345 && charVal <= 65370)
                    return charVal - 65345 + 97; //全角小写a-z
            }
            return charVal;
        }

        private bool isIgnorableCharacter_CN(char character)
        {
            //NOTE::
            //  中文表意字符的范围 4E00-9FA5
            int charVal = (int)character;
            return !(charVal >= 0x4e00 && charVal <= 0x9fa5);
        }

        #endregion


    }
}
